//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see http://www.gnu.org/licenses/.
// 

#include "SW.h"

Define_Module(SW);

void SW::initialize()
{
    // 设置 topology1 的路由表
    if (strcmp(getParentModule()->getName(), "topology1") == 0)
    {
        routing_table = {
            {LOCAL},
            {LOCAL},
            {LOCAL},
            {LOCAL},
            {WEST, LOCAL},
            {WEST, LOCAL},
            {WEST, LOCAL},
            {WEST, LOCAL},
            {NORTH, WEST, SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, WEST, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, LOCAL},
            {WEST, SOUTH, LOCAL},
            {WEST, SOUTH, LOCAL},
            {WEST, SOUTH, LOCAL},
            {WEST, SOUTH, LOCAL},
            {WEST, WEST, SOUTH, LOCAL},
            {WEST, WEST, SOUTH, LOCAL},
            {WEST, WEST, SOUTH, LOCAL},
            {WEST, WEST, SOUTH, LOCAL},
            {SOUTH, SOUTH, LOCAL},
            {SOUTH, SOUTH, LOCAL},
            {SOUTH, SOUTH, LOCAL},
            {SOUTH, SOUTH, LOCAL},
            {WEST, SOUTH, SOUTH, LOCAL},
            {WEST, SOUTH, SOUTH, LOCAL},
            {WEST, SOUTH, SOUTH, LOCAL},
            {WEST, SOUTH, SOUTH, LOCAL},
            {WEST, WEST, SOUTH, SOUTH, LOCAL},
            {WEST, WEST, SOUTH, SOUTH, LOCAL},
            {WEST, WEST, SOUTH, SOUTH, LOCAL},
            {WEST, WEST, SOUTH, SOUTH, LOCAL},
        };
    }
    // 设置 topology2 的路由表
    if (strcmp(getParentModule()->getName(), "topology2") == 0)
    {
        routing_table = {
            {LOCAL},
            {LOCAL},
            {LOCAL},
            {LOCAL},
            {WEST, LOCAL},
            {WEST, LOCAL},
            {WEST, LOCAL},
            {WEST, LOCAL},
            {NORTH, WEST, SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, WEST, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, LOCAL},
            {WEST, SOUTH, LOCAL},
            {WEST, SOUTH, LOCAL},
            {WEST, SOUTH, LOCAL},
            {WEST, SOUTH, LOCAL},
            {WEST, WEST, SOUTH, LOCAL},
            {WEST, WEST, SOUTH, LOCAL},
            {WEST, WEST, SOUTH, LOCAL},
            {WEST, WEST, SOUTH, LOCAL},
            {EAST, SOUTH, WEST, SOUTH, LOCAL},
            {EAST, SOUTH, WEST, SOUTH, LOCAL},
            {EAST, SOUTH, WEST, SOUTH, LOCAL},
            {EAST, SOUTH, WEST, SOUTH, LOCAL},
            {SOUTH, WEST, SOUTH, LOCAL},
            {SOUTH, WEST, SOUTH, LOCAL},
            {SOUTH, WEST, SOUTH, LOCAL},
            {SOUTH, WEST, SOUTH, LOCAL},
            {SOUTH, WEST, WEST, SOUTH, LOCAL},
            {SOUTH, WEST, WEST, SOUTH, LOCAL},
            {SOUTH, WEST, WEST, SOUTH, LOCAL},
            {SOUTH, WEST, WEST, SOUTH, LOCAL},
        };
    }
    // 设置 topology3 的路由表
    if (strcmp(getParentModule()->getName(), "topology3") == 0)
    {
        routing_table = {
            {LOCAL},
            {LOCAL},
            {LOCAL},
            {LOCAL},
            {WEST, LOCAL},
            {WEST, LOCAL},
            {WEST, LOCAL},
            {WEST, LOCAL},
            {NORTH, NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {NORTH, NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {NORTH, NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {NORTH, NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, LOCAL},
            {WEST, SOUTH, LOCAL},
            {WEST, SOUTH, LOCAL},
            {WEST, SOUTH, LOCAL},
            {WEST, SOUTH, LOCAL},
            {NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {EAST, SOUTH, WEST, SOUTH, LOCAL},
            {EAST, SOUTH, WEST, SOUTH, LOCAL},
            {EAST, SOUTH, WEST, SOUTH, LOCAL},
            {EAST, SOUTH, WEST, SOUTH, LOCAL},
            {SOUTH, WEST, SOUTH, LOCAL},
            {SOUTH, WEST, SOUTH, LOCAL},
            {SOUTH, WEST, SOUTH, LOCAL},
            {SOUTH, WEST, SOUTH, LOCAL},
            {WEST, SOUTH, SOUTH, WEST, LOCAL},
            {WEST, SOUTH, SOUTH, WEST, LOCAL},
            {WEST, SOUTH, SOUTH, WEST, LOCAL},
            {WEST, SOUTH, SOUTH, WEST, LOCAL},
        };
    }
    // 设置 topology4 的路由表
    if (strcmp(getParentModule()->getName(), "topology4") == 0)
    {
        routing_table = {
            {LOCAL},
            {LOCAL},
            {LOCAL},
            {LOCAL},
            {WEST, LOCAL},
            {WEST, LOCAL},
            {WEST, LOCAL},
            {WEST, LOCAL},
            {NORTH, NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {NORTH, NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {NORTH, NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {NORTH, NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, LOCAL},
            {SOUTH, WEST, LOCAL},
            {SOUTH, WEST, LOCAL},
            {SOUTH, WEST, LOCAL},
            {SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {NORTH, WEST, SOUTH, SOUTH, WEST, LOCAL},
            {EAST, SOUTH, SOUTH, WEST, LOCAL},
            {EAST, SOUTH, SOUTH, WEST, LOCAL},
            {EAST, SOUTH, SOUTH, WEST, LOCAL},
            {EAST, SOUTH, SOUTH, WEST, LOCAL},
            {SOUTH, SOUTH, WEST, LOCAL},
            {SOUTH, SOUTH, WEST, LOCAL},
            {SOUTH, SOUTH, WEST, LOCAL},
            {SOUTH, SOUTH, WEST, LOCAL},
            {WEST, SOUTH, SOUTH, WEST, LOCAL},
            {WEST, SOUTH, SOUTH, WEST, LOCAL},
            {WEST, SOUTH, SOUTH, WEST, LOCAL},
            {WEST, SOUTH, SOUTH, WEST, LOCAL},
        };
    }
}

void SW::handleMessage(cMessage *msg)
{
    // 对收到的包进行格式转换
    Packet *packet_received = check_and_cast<Packet *>(msg);

    // 若是无故障情况
    if (strcmp(getParentModule()->getName(), "topology0") == 0)
    {
        send_port = routeMessageXY(packet_received);
    }
    // 若是故障场景
    else
    {
        // 判断源节点
        int SRC;
        if (strcmp(packet_received->getSrc(), "dsp0") == 0) SRC = 0;
        else if (strcmp(packet_received->getSrc(), "dsp1") == 0) SRC = 1;
        else if (strcmp(packet_received->getSrc(), "dsp2") == 0) SRC = 2;
        else if (strcmp(packet_received->getSrc(), "dsp3") == 0) SRC = 3;
        else if (strcmp(packet_received->getSrc(), "dsp4") == 0) SRC = 4;
        else if (strcmp(packet_received->getSrc(), "dsp5") == 0) SRC = 5;
        else if (strcmp(packet_received->getSrc(), "dsp6") == 0) SRC = 6;
        else if (strcmp(packet_received->getSrc(), "dsp7") == 0) SRC = 7;
        else if (strcmp(packet_received->getSrc(), "dsp8") == 0) SRC = 8;
        else if (strcmp(packet_received->getSrc(), "dsp9") == 0) SRC = 9;
        else if (strcmp(packet_received->getSrc(), "dsp10") == 0) SRC = 10;
        else if (strcmp(packet_received->getSrc(), "dsp11") == 0) SRC = 11;
        else if (strcmp(packet_received->getSrc(), "dsp12") == 0) SRC = 12;
        else if (strcmp(packet_received->getSrc(), "dsp13") == 0) SRC = 13;
        else if (strcmp(packet_received->getSrc(), "dsp14") == 0) SRC = 14;
        else if (strcmp(packet_received->getSrc(), "dsp15") == 0) SRC = 15;
        else if (strcmp(packet_received->getSrc(), "dsp16") == 0) SRC = 16;
        else if (strcmp(packet_received->getSrc(), "dsp17") == 0) SRC = 17;
        else if (strcmp(packet_received->getSrc(), "dsp18") == 0) SRC = 18;
        else if (strcmp(packet_received->getSrc(), "dsp19") == 0) SRC = 19;
        else if (strcmp(packet_received->getSrc(), "dsp20") == 0) SRC = 20;
        else if (strcmp(packet_received->getSrc(), "dsp21") == 0) SRC = 21;
        else if (strcmp(packet_received->getSrc(), "dsp22") == 0) SRC = 22;
        else if (strcmp(packet_received->getSrc(), "dsp23") == 0) SRC = 23;
        else if (strcmp(packet_received->getSrc(), "dsp24") == 0) SRC = 24;
        else if (strcmp(packet_received->getSrc(), "dsp25") == 0) SRC = 25;
        else if (strcmp(packet_received->getSrc(), "dsp26") == 0) SRC = 26;
        else if (strcmp(packet_received->getSrc(), "dsp27") == 0) SRC = 27;
        else if (strcmp(packet_received->getSrc(), "dsp28") == 0) SRC = 28;
        else if (strcmp(packet_received->getSrc(), "dsp29") == 0) SRC = 29;
        else if (strcmp(packet_received->getSrc(), "dsp30") == 0) SRC = 30;
        else if (strcmp(packet_received->getSrc(), "dsp31") == 0) SRC = 31;
        else if (strcmp(packet_received->getSrc(), "dsp32") == 0) SRC = 32;
        else if (strcmp(packet_received->getSrc(), "dsp33") == 0) SRC = 33;
        else if (strcmp(packet_received->getSrc(), "dsp34") == 0) SRC = 34;
        else if (strcmp(packet_received->getSrc(), "dsp35") == 0) SRC = 35;

        send_port = routing_table[SRC][packet_received->getHopcnt()];
    }

    switch (send_port)
    {
        EV << "entering switch " << send_port << endl;
        case EAST:
            {
                // 跳数自增
                packet_received->setHopcnt(packet_received->getHopcnt() + 1);
                send(packet_received, "SW_inout_gate_east$o");
                break;
            }
        case WEST:
            {
                // 跳数自增
                packet_received->setHopcnt(packet_received->getHopcnt() + 1);
                send(packet_received, "SW_inout_gate_west$o");
                break;
            }
        case NORTH:
            {
                // 跳数自增
                packet_received->setHopcnt(packet_received->getHopcnt() + 1);
                send(packet_received, "SW_inout_gate_north$o");
                break;
            }
        case SOUTH:
            {
                // 跳数自增
                packet_received->setHopcnt(packet_received->getHopcnt() + 1);
                send(packet_received, "SW_inout_gate_south$o");
                break;
            }
        case LOCAL:
            {
                // 依次对比所连接的各个 dsp
                // 如果目的地址相同，则进行转发
                for (int i = 0; i < gateSize("SW_inout_gate_local"); i++)
                {
                    const char* dsp_name = gate("SW_inout_gate_local$o", i)->getNextGate()->getOwnerModule()->getName();
                    const char* result = packet_received->getDst();

                    if (strcmp(dsp_name, result) == 0)
                    {
                        send(packet_received, "SW_inout_gate_local$o", i);
                        break;
                    }
                }
            }
    }

}

int SW::routeMessageXY(Packet * packet_received)
{
    // 进行 XY 路由计算，判断下一跳的转发端口
    int local_x = par("x").intValue();
    int local_y = par("y").intValue();

    int dest_x = -1;
    int dest_y = -1;

    std::string dest_dsp = packet_received->getDst();


    EV << "entering topology0" << endl;

    // sw0
    if ((dest_dsp == "dsp0") or (dest_dsp == "dsp1") or (dest_dsp == "dsp2") or (dest_dsp == "dsp3"))
    {
        dest_x = 0;
        dest_y = 0;
    }
    // sw1
    else if ((dest_dsp == "dsp4") or (dest_dsp == "dsp5") or (dest_dsp == "dsp6") or (dest_dsp == "dsp7"))
    {
        dest_x = 1;
        dest_y = 0;
    }
    // sw2
    else if ((dest_dsp == "dsp8") or (dest_dsp == "dsp9") or (dest_dsp == "dsp10") or (dest_dsp == "dsp11"))
    {
        dest_x = 2;
        dest_y = 0;
    }
    // sw3
    else if ((dest_dsp == "dsp12") or (dest_dsp == "dsp13") or (dest_dsp == "dsp14") or (dest_dsp == "dsp15"))
    {
        dest_x = 0;
        dest_y = 1;
    }
    // sw4
    else if ((dest_dsp == "dsp16") or (dest_dsp == "dsp17") or (dest_dsp == "dsp18") or (dest_dsp == "dsp19"))
    {
        dest_x = 1;
        dest_y = 1;
    }
    // sw5
    else if ((dest_dsp == "dsp20") or (dest_dsp == "dsp21") or (dest_dsp == "dsp22") or (dest_dsp == "dsp23"))
    {
        dest_x = 2;
        dest_y = 1;
    }
    // sw6
    else if ((dest_dsp == "dsp24") or (dest_dsp == "dsp25") or (dest_dsp == "dsp26") or (dest_dsp == "dsp27"))
    {
        dest_x = 0;
        dest_y = 2;
    }
    // sw7
    else if ((dest_dsp == "dsp28") or (dest_dsp == "dsp29") or (dest_dsp == "dsp30") or (dest_dsp == "dsp31"))
    {
        dest_x = 1;
        dest_y = 2;
    }
    // sw8
    else if ((dest_dsp == "dsp32") or (dest_dsp == "dsp33") or (dest_dsp == "dsp34") or (dest_dsp == "dsp35"))
    {
        dest_x = 2;
        dest_y = 2;
    }

    // 进行路由计算
    if (dest_x != local_x)
    {
        if (dest_x > local_x) return EAST;
        else return WEST;
    }
    else if (dest_y != local_y)
    {
        if (dest_y > local_y) return NORTH;
        else return SOUTH;
    }
    else return LOCAL;


}
